#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/if.h>  // 用于网卡绑定
#include <sys/ioctl.h>  // 获取网卡IP

#define MULTICAST_GROUP "224.1.1.1"
#define PORT            12345
#define INTERFACE       "ens34"  // 指定接收网卡

int main(int argc, char* argv[])
{
    char ifc[32] = { 0 };
    if (argc != 2) {
        fprintf(stderr, "Usage: %s <interface>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    strncpy(ifc, argv[1], sizeof(ifc) - 1);

    int sockfd;
    struct sockaddr_in local_addr;
    struct ip_mreqn mreq;
    char buffer[1024];
    socklen_t addr_len = sizeof(local_addr);

    // 1. 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 2. 绑定到本地所有IP的指定端口
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 监听所有网卡
    local_addr.sin_port = htons(PORT);

    if (bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 3. 获取指定网卡（ens34）的IP地址（关键步骤）
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(ifr));
    strncpy(ifr.ifr_name, ifc, IFNAMSIZ);
    if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
        perror("ioctl(SIOCGIFADDR) failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    struct sockaddr_in* iface_ip = (struct sockaddr_in*)&ifr.ifr_addr;

    // 4. 加入组播组并绑定到ens34
    memset(&mreq, 0, sizeof(mreq));
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    mreq.imr_address = iface_ip->sin_addr;  // 使用ens34的IP
    mreq.imr_ifindex = if_nametoindex(ifc);  // 绑定到ens34的接口索引

    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt(IP_ADD_MEMBERSHIP) failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    // 5. 接收组播数据
    printf("Listening for multicast on %s:%d via %s...\n",
        MULTICAST_GROUP, PORT, ifc);

    ssize_t recv_len;
    while (1) {
        recv_len = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0,
            (struct sockaddr*)&local_addr, &addr_len);
        if (recv_len < 0) {
            perror("recvfrom failed");
            break;
        }
        buffer[recv_len] = '\0';
        printf("Received: %s\n", buffer);
    }

    close(sockfd);
    return 0;
}